<?php
// +---------------------------------------------------------------------
// | Author: 卫聪 <438608613@qq.com>
// +---------------------------------------------------------------------

namespace Tree;
use think\Db;
use think\Cache;
/**
 * 通用无限分类树形类
 * $config['table']; //表名
 * $config['key']; //主键字段
 * $config['parent_field'] //关联父级的字段
 * @example
 * $tree = new \Category\Library\Tree(array(
    'table' => 'category',
    'key' => 'id',
    'order' => 'listorder',
    'parent_field' => 'parentid',
    ));
    $tree->tree_to_html('select' ,$tree->tree);
 */
class Tree{

    private $config;
    public $tree;
    public $top;

    public function __construct($config){

        $this->config = $config;
        if(!$config || !is_array($config)){
            throw new \think\Exception('config必须是数组');
        }

        $this->field = isset($this->config['field']) ? $this->config['field'] :'*';
        $this->order = isset($this->config['order']) ? $this->config['order'] :'listorder asc';
        $this->where = isset($this->config['where'])?$this->config['where']:'';
        //无限层级不能有limit 否则遍历成 树形状态时候，会有找不到的父级 或者 子集的情况
        //$this->limit = isset($this->config['limit'])?$this->config['limit']: '';



        if(is_array($this->where)){
            $where = array_merge($this->where,[]);
        }else{
            $where = $this->where;
        }


        $this->res = Db::name($this->config['table'])
            ->field($this->field)
            ->where($where)
            ->order($this->order)
           // ->limit($this->limit)
            ->select();



        if(!$this->res){
            $this->tree = '';
        }else{
            $this->tree = $this->get_tree($this->res);
        }




    }

/*
 * 非递归 遍历出树装形态
 * arr 数据
 */
    public function get_tree($arr){

            $tree = array();
            //第一步，将分类id作为数组key,并创建children单元
            foreach($arr as $v){
                $tree[$v['id']] = $v;
                $tree[$v['id']]['son'] = array();
            }
            //第二步，利用引用，将每个分类添加到父类children数组中，这样一次遍历即可形成树形结构。
            foreach($tree as $key=>$item){

                $tree[$key]['url'] = url(''.$item['module'].'/'.$item['controller'].'/'.$item['action'].'');

                if($item[$this->config['parent_field']] != 0){
                    $tree[$item[$this->config['parent_field']]]['son'][] = &$tree[$key];//注意：此处必须传引用否则结果不对
                    if($tree[$key]['son'] == null){
                        unset($tree[$key]['son']); //如果children为空，则删除该children元素（可选）
                    }
                }
            }
           
            //第三步，删除无用的非根节点数据
            foreach($tree as $key=>$category){
                if(isset($category[$this->config['parent_field']]) && $category[$this->config['parent_field']] != 0){
                    unset($tree[$key]);
                }
            }

            //重新排序 key 从 0 开始
            $return = [];
            foreach($tree as $k => $v){
                $return[] = $v;
            }



            return $return;

    }

    /*
     * 树形结构数据遍历成对应html
     */
    public function tree_to_html($type , $tree ,$select_id = ''){
        $str = '';
        if(!$tree) return ;

        switch($type){
            //通用的select 选项
            case 'select':
                foreach($tree as $k => $v) {
                    $spacer = $this->build_space($v);

                    if($select_id == $v['id']){
                        $str .= '<option value="'.$v['id'].'" selected>'.$spacer . $v['name'] .'</option>';
                    }else{
                        $str .= '<option value="'.$v['id'].'">'.$spacer . $v['name'].'</option>';
                    }

                    if (isset($v['son']) ) {
                        $str .= $this->tree_to_html($type, $v['son'] ,$select_id);
                    }
                }

                break;
            //后台菜单管理的table
            case 'menu_table':

                foreach($tree as $k => $v){

                    $spacer = $this->build_space($v);
                    $v['isshow'] = $v['isshow'] ? '隐藏' :'显示';

                    $str .= '<tr>
                            <td></td>
                            <td>'.$v['listorder'].'</td>
                            <td>'.$v['id'].'</td>
                            <td>'.$spacer.' <a href="javascript:;" >'.$v['name'].'</a></td>
                            <td>'.$v['module'].'</td>
                            <td>'.$v['controller'].'</td>
                            <td>'.$v['action'].'</td>
                            <td>'.$v['isshow'].'</td>
                            
                        </tr>';
                    if(isset($v['son'])){
                        $str .= $this->tree_to_html($type ,$v['son']);
                    }
                }
                break;
            //后台左侧菜单导航
            case 'admin_menu':

                $res = Db::name($this->config['table'])->field('id,path')->where($select_id)->find();

                if($res){
                    $pid = explode(',',$res['path']);
                    $sid = $res['id'];
                }else{
                    $pid = $sid = '';
                }
                $data_id = 0;
                foreach($tree as $k => $v){

                        if($pid == $v['id']){
                            $active = 'active';
                        }else{
                            $active = '';
                        }
                        $url = url($v['module'].'/'.$v['controller'].'/'.$v['action']);
                        $str .= '<li class="layui-nav-item '.$active.'">
                                    <a href="javascript:;">
                                    <i class="layui-icon">&#xe647;</i>&nbsp;&nbsp;<span>'.$v['name'].'</span>';

                        if(isset($v['son'])){
                            $str .= '<span class="pull-right-container">
                                        <i class="fa fa-angle-left pull-right"></i>
                                    </span>';
                        }

                       $str .= '</a>';
                       if(isset($v['son'])){
                           $str .= '<dl class="layui-nav-child">';
                           foreach($v['son'] as $sk => $sv){
                               if(isset($sv['son'])){
                                   $str .= $this->tree_to_html($type,$sv['son']);
                               }else{

                                   if($sid == $sv['id']){
                                       $active = 'active';
                                   }else{
                                       $active = '';
                                   }

                                   $url = url($sv['module'].'/'.$sv['controller'].'/'.$sv['action']);
                                   $str .= '
                                           <dd data-url="'.$url.'" data-id="'.$data_id.'" data-hash="'.md5($url).'"><a href="javascript:;">
                                                <i class="layui-icon">&#xe602;</i> <span>'.$sv['name'].'</span></a>
                                            </dd>
                                       ';
                               }

                               $data_id++;
                           }
                           $str .= '</dl> ';
                       }

                       $str .= '</li>';


                }

                break;

        }

        return $str;
    }

    /*
     * 生成空格层级字符串
     */
    public function build_space($v){
        $spacer = '';
        if($v[$this->config['parent_field']] == '0'){
            $spacer .= '';
        }else{
            $path = explode(',',$v['path']);
                $spacer .= '&nbsp;&nbsp;';
            for($i = 0 ;$i < count($path)-1 ;$i++ ){
                $spacer .= '&nbsp;&nbsp;&nbsp;&nbsp;';
            }
            $spacer .= '|- ';
        }

        return $spacer;
    }






}



